package com.hsogoo.collate.utils;

import com.hsogoo.collate.domain.SftpBean;
import com.jcraft.jsch.*;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties;

public class SftpUtil {
    private static Logger logger = LoggerFactory.getLogger(SftpUtil.class);


    public static boolean upload(SftpBean bean, String remoteFilePath, InputStream localInputStream) {
        logger.info("put stream to remoteFilePath : {}", remoteFilePath);
        if (StringUtils.isBlank(remoteFilePath)) {
            logger.warn("远程文件地址不能为空");
            return false;
        }
        if (localInputStream==null) {
            logger.warn("本地流不能为空");
            return false;
        }
        if (!bean.validate()) {
            logger.warn("登陆远程服务器配置信息校验失败");
            return false;
        }
        Session session = null;
        Channel channel = null;
        try {
            JSch jsch = new JSch();
            session = jsch.getSession(bean.getUsername(), bean.getRemoteAddress(), bean.getRemotePort());

            SftpUserInfo userInfo = new SftpUserInfo(bean.getPassword());
            session.setUserInfo(userInfo);
            session.setTimeout(10000);
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            // 跳过身份验证提示
            config.put("PreferredAuthentications","publickey,keyboard-interactive,password");
            session.setConfig(config);

            session.connect();

            SftpProgressMonitor monitor = new FileProgressMonitor();

            channel = session.openChannel("sftp");
            channel.connect();
            ChannelSftp c = (ChannelSftp) channel;

            int mode = 0;

            // 递归创建远程目录
            int index = remoteFilePath.lastIndexOf("/");
            if (index < 0) {
                index = 0;
            }
            String remoteDir = remoteFilePath.substring(0, index);
            try {
                c.lstat(remoteDir);
            } catch (SftpException e) {
                // 目录不存在
                if (e.id == 2) {
                    logger.debug("SftpUtils uploadFile create directoy [{}]", remoteDir);
                    mkdirs(c, remoteDir);
                }
            }

            c.put(localInputStream, remoteFilePath, monitor, mode);
        } catch (Exception e) {
            logger.error("SFTP文件上传失败，失败信息：", e);
            return false;
        } finally {
            if ((session != null) && (session.isConnected())) {
                session.disconnect();
            }
        }
        logger.info("SFTP文件上传完成...");
        return true;
    }
    public static boolean upload(SftpBean bean, String remoteFilePath, String localFilePath) {
        logger.info("remoteFilePath : {},localFilePath : {}", remoteFilePath, localFilePath);
        if (StringUtils.isBlank(remoteFilePath)) {
            logger.warn("远程文件地址不能为空");
            return false;
        }
        if (StringUtils.isBlank(localFilePath)) {
            logger.warn("本地文件地址不能为空");
            return false;
        }
        if (!bean.validate()) {
            logger.warn("登陆远程服务器配置信息校验失败");
            return false;
        }
        Session session = null;
        Channel channel = null;
        try {
            JSch jsch = new JSch();
            session = jsch.getSession(bean.getUsername(), bean.getRemoteAddress(), bean.getRemotePort());

            SftpUserInfo userInfo = new SftpUserInfo(bean.getPassword());
            session.setUserInfo(userInfo);
            session.setTimeout(10000);
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            // 跳过身份验证提示
            config.put("PreferredAuthentications","publickey,keyboard-interactive,password");
            session.setConfig(config);

            session.connect();

            SftpProgressMonitor monitor = new FileProgressMonitor();

            channel = session.openChannel("sftp");
            channel.connect();
            ChannelSftp c = (ChannelSftp) channel;

            int mode = 0;

            // 递归创建远程目录
            int index = remoteFilePath.lastIndexOf("/");
            if (index < 0) {
                index = 0;
            }
            String remoteDir = remoteFilePath.substring(0, index);
            try {
                c.lstat(remoteDir);
            } catch (SftpException e) {
                // 目录不存在
                if (e.id == 2) {
                    logger.debug("SftpUtils uploadFile create directoy [{}]", remoteDir);
                    mkdirs(c, remoteDir);
                }
            }

            c.put(localFilePath, remoteFilePath, monitor, mode);
        } catch (Exception e) {
            logger.error("SFTP文件上传失败，失败信息：", e);
            return false;
        } finally {
            if ((session != null) && (session.isConnected())) {
                session.disconnect();
            }
        }
        logger.info("SFTP文件上传完成...");
        return true;
    }

    /**
     * 递归创建目录
     *
     * @param sftp       ChannelSftp
     * @param remotePath 远程路径
     */
    private static void mkdirs(ChannelSftp sftp, String remotePath) throws SftpException {
        if (remotePath.startsWith("/")) {
            sftp.cd("/");
        }
        String[] folders = remotePath.split("/");
        for (String folder : folders) {
            if (folder.length() > 0) {
                try {
                    sftp.cd(folder);
                } catch (SftpException e) {
                    sftp.mkdir(folder);
                    sftp.cd(folder);
                }
            }
        }
    }

    public static boolean download(SftpBean bean, String remoteFilePath, String localFilePath) {
        if (StringUtils.isBlank(remoteFilePath)) {
            logger.warn("远程文件地址不能为空");
            return false;
        }
        if (StringUtils.isBlank(localFilePath)) {
            logger.warn("本地文件地址不能为空");
            return false;
        }
        if (!bean.validate()) {
            logger.warn("登陆远程服务器配置信息校验失败");
            return false;
        }
        Session session = null;
        Channel channel = null;
        try {
            JSch jsch = new JSch();
            session = jsch.getSession(bean.getUsername(), bean.getRemoteAddress(), bean.getRemotePort());

            SftpUserInfo userInfo = new SftpUserInfo(bean.getPassword());
            session.setUserInfo(userInfo);

            session.setTimeout(10000);
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            // 跳过身份验证提示
            config.put("PreferredAuthentications","publickey,keyboard-interactive,password");
            session.setConfig(config);

            session.connect();

            SftpProgressMonitor monitor = new FileProgressMonitor();

            channel = session.openChannel("sftp");
            channel.connect();
            ChannelSftp c = (ChannelSftp) channel;

            int mode = 0;

            c.get(remoteFilePath, localFilePath, monitor, mode);
        } catch (Exception e) {
            logger.warn("SFTP下载文件失败，失败信息：", e);
            return false;
        } finally {
            if ((session != null) && (session.isConnected())) {
                session.disconnect();
            }
        }
        logger.info("SFTP文件下载完成");
        return true;
    }

    public static boolean download(SftpBean bean, String remoteFilePath, OutputStream localOutputStream) {
        if (StringUtils.isBlank(remoteFilePath)) {
            logger.warn("远程文件地址不能为空");
            return false;
        }
        if (localOutputStream==null) {
            logger.warn("写入流不能为空");
            return false;
        }

        if (!bean.validate()) {
            logger.warn("登陆远程服务器配置信息校验失败");
            return false;
        }
        Session session = null;
        Channel channel = null;
        try {
            JSch jsch = new JSch();
            session = jsch.getSession(bean.getUsername(), bean.getRemoteAddress(), bean.getRemotePort());

            SftpUserInfo userInfo = new SftpUserInfo(bean.getPassword());
            session.setUserInfo(userInfo);

            session.setTimeout(10000);
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            // 跳过身份验证提示
            config.put("PreferredAuthentications","publickey,keyboard-interactive,password");
            session.setConfig(config);

            session.connect();

            SftpProgressMonitor monitor = new FileProgressMonitor();

            channel = session.openChannel("sftp");
            channel.connect();
            ChannelSftp c = (ChannelSftp) channel;

            int mode = 0;

            c.get(remoteFilePath, localOutputStream, monitor, mode,0);
        } catch (Exception e) {
            logger.warn("SFTP下载文件失败，失败信息：", e);
            return false;
        } finally {
            if ((session != null) && (session.isConnected())) {
                session.disconnect();
            }
        }
        logger.info("SFTP文件下载完成");
        return true;
    }

    public static class FileProgressMonitor implements SftpProgressMonitor {
        long count = 0L;
        long max = 0L;
        private long percent = -1L;

        @Override
        public void init(int op, String src, String dest, long max) {
            this.max = max;
            this.count = 0L;
            this.percent = -1L;
        }

        @Override
        public boolean count(long count) {
            this.count += count;
            if (this.percent >= this.count * 100L / this.max) {
                return true;
            }
            this.percent = (this.count * 100L / this.max);
            SftpUtil.logger.info("文件传输比例" + this.percent);

            return this.percent != 100L;
        }

        @Override
        public void end() {
        }
    }
}